using System.Net;
using System.Text.Json;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
using Grpc.Net.ClientFactory;
using OrderServiceClient = Order.OrderService.OrderServiceClient;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<ClientLoggerInterceptor>();
//使用ClientFactory的方式创建客户端
builder.Services
    .AddGrpcClient<OrderServiceClient>("order", o =>
    {
        o.Address = new Uri("http://localhost:5001");
        //配置侦听器，需指定scope范围，效果同AddInterceptor
        o.InterceptorRegistrations.Add(new InterceptorRegistration(InterceptorScope.Channel,
            sp => sp.GetRequiredService<ClientLoggerInterceptor>()));
        o.ChannelOptionsActions.Clear();
        o.CallOptionsActions.Clear();
        //可以使用一个委托覆盖客户端的创建方式
        o.Creator = null;
    })
    .ConfigureChannel(o =>
    {
        //Channel配置详情参阅
        //https://learn.microsoft.com/zh-cn/aspnet/core/grpc/configuration?view=aspnetcore-9.0
        o.HttpHandler = new SocketsHttpHandler()
        {
            //保持活动 ping 仅有助于使连接保持活动状态。 连接上长时间运行的 gRPC 调用可能仍会因不活动而被服务器或中间代理终止。
            PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan,
            KeepAlivePingDelay = TimeSpan.FromSeconds(60),
            KeepAlivePingTimeout = TimeSpan.FromSeconds(30),
            //设置为 true，则当达到并发流限制时，通道会创建额外的 HTTP/2 连接。
            EnableMultipleHttp2Connections = true
        };
    })
    .ConfigureHttpClient(o =>
    {
        o.Timeout = TimeSpan.FromSeconds(60);
        o.MaxResponseContentBufferSize = int.MaxValue;
    })
    //添加侦听器,需要提前在di容器中注册,默认为Channel作用域
    //.AddInterceptor<ClientLoggerInterceptor>(InterceptorScope.Client)
    //传播截止时间和取消令牌，确保复杂的嵌套 gRPC 场景始终传播截止时间和取消的一种极佳方式
    .EnableCallContextPropagation(x => x.SuppressContextNotFoundErrors = true);
var app = builder.Build();

//测试grpc客户端工厂
using var scope = app.Services.CreateScope();
var factory = scope.ServiceProvider.GetRequiredService<GrpcClientFactory>();
var client = factory.CreateClient<OrderServiceClient>("order");
await CreateOrderAsync();
await GetAllOrderAsync();
//直接注入client
client = scope.ServiceProvider.GetRequiredService<OrderServiceClient>();
await CreateOrderAsync();
await GetAllOrderAsync();
//测试直接使用GrpcChannel创建客户端
using var channel = GrpcChannel.ForAddress("http://localhost:5001");
client = new OrderServiceClient(channel);
await CreateOrderAsync();
await GetAllOrderAsync();
//app.Run();
return;

async Task CreateOrderAsync()
{
    var resp = await client.CreateOrderAsync(new Model.CreateOrderRequest
        {
            Name = "test",
            Price = 100,
            Description = "test",
        },
        new CallOptions(
            headers: new Metadata { new Metadata.Entry("token", "123456") }
            //调用结束的最后期限（截止时间）
            //注意：必须有一个DateTimeKind，DateTimeKind.UTC,或使用DateTime.MaxValue
            , deadline: DateTime.UtcNow.AddSeconds(10)
            , cancellationToken: CancellationToken.None
            //WriteFlags.BufferHint 提示写操作可能被缓冲，不需要立即在线路上发出。
            //WriteFlags.NoCompress 强制为特定的写入禁用压缩。
            , new WriteOptions(WriteFlags.NoCompress)
            //core已经不在支持
            , propagationToken: null
            //客户端调用凭据，提供调用粒度的授权
            , credentials: null
        ));
    Console.WriteLine("grpc调用响应结果：" + JsonSerializer.Serialize(resp));
}

async Task GetAllOrderAsync()
{
    var resp = await client.GetAllOrdersAsync(new Empty());
    Console.WriteLine("grpc调用响应结果：" + JsonSerializer.Serialize(resp));
}